﻿using System;
using IvyBus;
using System.Windows.Media.Media3D;

namespace DisplayInteraction1
{
    class ModelProto1 : InterfaceProto
    {
        private static readonly int constanteRobustesse = 2;
        private static Ivy bus;
        private static Boolean handOpened = true;
        private static Point3D handPos;
        private String adresse;
        private static MainWindow window;
        private static bool displayReady = false;
        private static bool kinectReady = false;

        private static double angle;
        private static double maxDangle = 60;

        private static int nbFingers = -1;
        private static int nbFingers2 = -1;
        private static int cdVerif = constanteRobustesse;
        private static int cdVerif2 = constanteRobustesse;

        private static double limitLeft, limitRight;
        private static readonly double segmentSizeResize = 2;

        public ModelProto1(String adresse, MainWindow window)
        {
            this.adresse = adresse;
            ModelProto1.window = window;
            bus = new Ivy("MODELPROTO11", "MODELPROTO11 READY");
        }

        public void start()
        {
            bus.Start(this.adresse);
            bus.BindMsg("^IHM_EVENT=(.*)", viewReady);
            bus.BindMsg("^USER_EVENT=(.*)", user);
            bus.BindMsg("^USER_NB_FINGERS=(.*) USER_FINGER1_ANGLE=(.*)", fingerAngleEvent);
            bus.BindMsg("^HAND_POSITION X=(.*) Y=(.*) Z=(.*)", newRightHandPosition);
        }

        public void stop()
        {
            bus.UnbindMsg("^IHM_EVENT=(.*)");
            bus.UnbindMsg("^USER_EVENT=(.*)");
            bus.UnbindMsg("^USER_FINGER_ANGLE=(.*)");
            bus.UnbindMsg("^HAND_POSITION X=(.*) Y=(.*) Z=(.*)");
            bus.SendMsg("KINECT_EVENT=USER_LOST");
            bus.SendMsg("KINECT_EVENT=KINECT_DISCONNECTED");
            displayReady = false;
            kinectReady = false;
            getReady();
            bus.Stop();
        }

        private static void getReady()
        {
            window.majFeedbackConnection(displayReady, kinectReady);
        }

        private static void send(String s)
        {
            try
            {
                if (displayReady)
                {
                    bus.SendMsg(s);
                }
            }
            catch (InvalidOperationException e)
            {
                Console.WriteLine("Erreur envoir message proto1 : " + s + "\r\n" + e.Message);
            }
        }

        EventHandler<IvyMessageEventArgs> viewReady = new EventHandler<IvyMessageEventArgs>(t0);
        static void t0(Object o, IvyMessageEventArgs a)
        {
            switch (a.GetArguments()[0])
            {
                case "ASK_CONNECTION":
                    displayReady = true;
                    Console.WriteLine("ASK_CONNECTION RECU, displayReady = " + displayReady);
                    getReady();
                    send("KINECT_EVENT=KINECT_CONNECTED");
                    if (kinectReady) send("KINECT_EVENT=USER_DETECTED");
                    break;
                case "END_CONNECTION":
                    displayReady = false;
                    getReady();
                    break;
                default:
                    Console.WriteLine("PROTO 1 : SYNTAXE ERROR MESSAGE IVY IHM_EVENT");
                    break;
            }
        }

        EventHandler<IvyMessageEventArgs> user = new EventHandler<IvyMessageEventArgs>(t1);
        static void t1(Object o, IvyMessageEventArgs a)
        {
            switch (a.GetArguments()[0])
            {
                case "DETECTED":
                    kinectReady = true;
                    getReady();
                    bus.SendMsg("KINECT_EVENT=USER_DETECTED");
                    break;
                case "LOST":
                    kinectReady = false;
                    getReady();
                    bus.SendMsg("KINECT_EVENT=USER_LOST");
                    break;
                case "CLICK":
                    send("KINECT_EVENT=PUSH");
                    break;
                default:
                    Console.WriteLine("PROTO 1 : SYNTAXE ERROR MESSAGE IVY USER_EVENT");
                    break;
            }
        }

        EventHandler<IvyMessageEventArgs> newRightHandPosition = new EventHandler<IvyMessageEventArgs>(t2);
        static void t2(Object o, IvyMessageEventArgs a)
        {
            handPos = new Point3D(Double.Parse(a.GetArguments()[0]), Double.Parse(a.GetArguments()[1]), Double.Parse(a.GetArguments()[2]));
            send("KINECT_POSITION X=" + a.GetArguments()[0] + " Y=" + a.GetArguments()[1] + " Z=" + a.GetArguments()[2]);
            majMain();
        }

        EventHandler<IvyMessageEventArgs> fingerAngleEvent = new EventHandler<IvyMessageEventArgs>(t6);
        static void t6(Object o, IvyMessageEventArgs a)
        {
            int nbFingersTemp = int.Parse(a.GetArguments()[0]);
            //Console.WriteLine("Nb doigts reçu : " + nbFingersTemp);
            if (nbFingersTemp != nbFingers)
            {
                if (nbFingersTemp == nbFingers2)
                {
                    if (cdVerif > 0)
                    {
                        cdVerif--;
                    }
                    else if (nbFingersTemp == 0 && nbFingers == 1)
                    {
                        send("KINECT_HAND_OPENED=false");
                        handOpened = false;
                        cdVerif = constanteRobustesse;
                        nbFingers = nbFingersTemp;
                    } 
                    else
                    {
                        cdVerif = constanteRobustesse;
                        nbFingers = nbFingersTemp;
                        if (nbFingers == 1)// && !handOpened)
                        {
                            angle = Double.Parse(a.GetArguments()[1]);
                            limitLeft = angle - segmentSizeResize / 2;
                            limitRight = angle + segmentSizeResize / 2;
                            send("KINECT_FINGER_ANGLE=" + angle);
                        }
                        else if (nbFingers != 1)
                        {
                            if (nbFingers == 0)// && handOpened)
                            {
                                send("KINECT_HAND_OPENED=false");
                                handOpened = false;
                            }
                            else if (nbFingers > 1)// && !handOpened)
                            {
                                send("KINECT_HAND_OPENED=true");
                                handOpened = true;
                            }
                        }
                    }
                }
                else
                {
                    nbFingers2 = nbFingersTemp;
                    cdVerif = constanteRobustesse;
                }
            }
            else if (nbFingers == 1)
            {
                nbFingers2 = nbFingersTemp;
                changeAngle(Double.Parse(a.GetArguments()[1]));
            }

            /*
            if (nbFingersTemp == 1 && nbFingers != 1)
            {
                if (cdVerif > 0) cdVerif--;
                else
                {
                    nbFingers = nbFingersTemp;
                    cdVerif = constanteRobustesse;
                    cdVerif2 = constanteRobustesse;
                    if (!handOpened)
                    {
                        angle = Double.Parse(a.GetArguments()[1]);
                        limitLeft = angle - segmentSizeResize / 2;
                        limitRight = angle + segmentSizeResize / 2;
                        send("KINECT_FINGER_ANGLE=" + angle);
                    }
                }
            }
            else if (nbFingersTemp != 1)
            {
                if (nbFingers == 1)
                {
                    if (cdVerif2 > 0) cdVerif2--;
                    else
                    {
                        nbFingers = nbFingersTemp;
                        cdVerif = constanteRobustesse;
                        cdVerif2 = constanteRobustesse;
                        if (nbFingers == 0)
                        {
                            send("KINECT_HAND_OPENED=false");
                            handOpened = false;
                        }
                        else if (nbFingers > 1)
                        {
                            send("KINECT_HAND_OPENED=true");
                            handOpened = true;
                        }
                    }
                }
                else
                {
                    cdVerif = constanteRobustesse;
                    cdVerif2 = constanteRobustesse;
                    nbFingers = nbFingersTemp;
                    if (nbFingers == 0 && handOpened)
                    {
                        send("KINECT_HAND_OPENED=false");
                        handOpened = false;
                    }
                    else if (nbFingers > 1 && !handOpened)
                    {
                        send("KINECT_HAND_OPENED=true");
                        handOpened = true;
                    }
                }
            }
            else
            {
                cdVerif = constanteRobustesse;
                cdVerif2 = constanteRobustesse;
                changeAngle(Double.Parse(a.GetArguments()[1]));
            }
             * */
        }

        private static void changeAngle(double a)
        {
            if (a >= (angle - maxDangle) && a <= (angle + maxDangle))
            {
                angle = a;
                if (a < limitLeft)
                {
                    send("KINECT_FINGER_ANGLE=" + (limitLeft + limitRight) / 2);
                    limitLeft = a;
                    limitRight = limitLeft + segmentSizeResize;
                }
                else if (a > limitRight)
                {
                    send("KINECT_FINGER_ANGLE=" + (limitLeft + limitRight) / 2);
                    limitRight = a;
                    limitLeft = limitRight - segmentSizeResize;
                }
            }
        }

        private static double distance(Point3D p1, Point3D p2)
        {
            return Math.Sqrt((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y));
        }

        private static void majMain() {
            if (nbFingers == 1 && !handOpened) window.majMainDroite("FINGER_ON", (int)handPos.X, (int)handPos.Y);
            else if (nbFingers == 1 && handOpened) window.majMainDroite("FINGER_OFF", (int)handPos.X, (int)handPos.Y);
            else if (handOpened) window.majMainDroite("OPENED", (int)handPos.X, (int)handPos.Y);
            else window.majMainDroite("CLOSED", (int)handPos.X, (int)handPos.Y);
        }
    }
}
